package io.github.wanggit.antrpc.console.zookeeper;

import io.github.wanggit.antrpc.commons.bean.SubscribeNode;
import io.github.wanggit.antrpc.console.web.vo.SubscribeNodeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
@Component
public class DefaultSubscribeContainer implements ISubscribeContainer {

    private final ConcurrentHashMap<String, CopyOnWriteArrayList<SubscribeNodeVO>> nodes =
            new ConcurrentHashMap<>();

    @Override
    public void addSubscribeNode(SubscribeNode subscribeNode) {
        if (null == subscribeNode) {
            throw new IllegalArgumentException("argument not be null.");
        }
        if (!nodes.containsKey(subscribeNode.getClassName())) {
            nodes.put(subscribeNode.getClassName(), new CopyOnWriteArrayList<>());
        }
        SubscribeNodeVO subscribeNodeVO = SubscribeNodeVO.fromSubscribeNode(subscribeNode);
        CopyOnWriteArrayList<SubscribeNodeVO> vos = nodes.get(subscribeNode.getClassName());
        remove(vos, subscribeNodeVO);
        vos.add(subscribeNodeVO);
    }

    @Override
    public void deleteSubscribeNode(SubscribeNode subscribeNode) {
        if (null == subscribeNode) {
            throw new IllegalArgumentException("argument not be null.");
        }
        if (nodes.containsKey(subscribeNode.getClassName())) {
            CopyOnWriteArrayList<SubscribeNodeVO> treeSet = nodes.get(subscribeNode.getClassName());
            SubscribeNodeVO subscribeNodeVO = SubscribeNodeVO.fromSubscribeNode(subscribeNode);
            remove(treeSet, subscribeNodeVO);
            if (treeSet.isEmpty()) {
                nodes.remove(subscribeNode.getClassName());
            }
        }
    }

    @Override
    public List<SubscribeNodeVO> findByClassName(String className) {
        CopyOnWriteArrayList<SubscribeNodeVO> subscribeNodeVOS = nodes.get(className);
        if (null == subscribeNodeVOS || subscribeNodeVOS.isEmpty()) {
            return new ArrayList<>();
        }
        return new ArrayList<>(subscribeNodeVOS);
    }

    @Override
    public SubscribeNodeVO findByClassNameAndHost(String className, String appNameHostInfo) {
        List<SubscribeNodeVO> subscribeNodeVOS = findByClassName(className);
        if (subscribeNodeVOS.isEmpty()) {
            return null;
        }
        return subscribeNodeVOS.stream()
                .filter(it -> Objects.equals(it.getHost(), appNameHostInfo))
                .findFirst()
                .orElse(null);
    }

    private void remove(
            CopyOnWriteArrayList<SubscribeNodeVO> vos, SubscribeNodeVO subscribeNodeVO) {
        int idx = -1;
        for (int i = 0; i < vos.size(); i++) {
            SubscribeNodeVO nodeVO = vos.get(i);
            if (Objects.equals(nodeVO.getHost(), subscribeNodeVO.getHost())
                    && Objects.equals(nodeVO.getClassName(), subscribeNodeVO.getClassName())) {
                idx = i;
                break;
            }
        }
        if (idx > -1) {
            vos.remove(idx);
        }
    }
}
